package com.stroke.graphics;

import com.stroke.core.InputHandler;
import com.stroke.core.Configuration;
import org.apache.log4j.Logger;

import javax.swing.*;
import java.awt.*;
import java.util.Map;

/**
 * Author: Igor Bubelov
 * Date: 3/5/11 10:11 PM
 */
public class ScreenManager {
    private Configuration configuration;
    private Screen screen;
    private Rectangle viewArea;
    private InputHandler inputHandler;

    public ScreenManager(Configuration configuration) {
        this.configuration = configuration;

        screen = new Screen(configuration.getScreenWidth(), configuration.getScreenHeight());
        viewArea = new Rectangle(0, 0, configuration.getScreenWidth(), configuration.getScreenHeight());
        inputHandler = new InputHandler();

        if (configuration.isFullScreen()) {
            setFullScreen();
        } else {
            setWindowed();
        }
    }

    private void setFullScreen() {
        GraphicsEnvironment env = GraphicsEnvironment.getLocalGraphicsEnvironment();
        GraphicsDevice device = env.getDefaultScreenDevice();

        if (device.isFullScreenSupported()) {
            DisplayMode defaultMode = device.getDisplayMode();

            if (defaultMode.getWidth() == configuration.getScreenWidth()
                    && defaultMode.getHeight() == configuration.getScreenHeight()) {
                screen.pack();
                device.setFullScreenWindow(screen);
                initInput();
                return;
            } else {
                if (device.isDisplayChangeSupported()) {
                    for (int i = 0; i < device.getDisplayModes().length; i++) {
                        DisplayMode current = device.getDisplayModes()[i];

                        if (current.getWidth() == configuration.getScreenWidth()
                                && current.getHeight() == configuration.getScreenHeight()) {
                            device.setDisplayMode(current);
                            screen.pack();
                            device.setFullScreenWindow(screen);
                            initInput();
                            return;
                        }
                    }

                    Logger.getLogger(getClass()).error("Full graphics mode doesn't allowed with such resolution. Switching to windowed...");
                    setWindowed();
                    return;
                } else {
                    Logger.getLogger(getClass()).error("Display mode changing doesn't supported. Switching to windowed...");
                    setWindowed();
                    return;
                }
            }
        } else {
            Logger.getLogger(getClass()).error("Full graphics mode doesn't supported. Switching to windowed...");
            setWindowed();
            return;
        }
    }

    private void setWindowed() {
        screen.pack();

        screen.setLocationRelativeTo(null);

        screen.getCanvas().createBufferStrategy(2);

        initInput();
    }

    private void initInput() {
        screen.addKeyListener(inputHandler);
        screen.addMouseListener(inputHandler);
        screen.addMouseMotionListener(inputHandler);
        screen.addMouseWheelListener(inputHandler);

        Map<KeyStroke, Action> keyMap = configuration.getKeyMap();
        InputMap inputMap = screen.getRootPane().getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW);

        for (KeyStroke stroke : keyMap.keySet()) {
            Action action = keyMap.get(stroke);

            inputMap.put(stroke, action.toString());

            screen.getRootPane().getActionMap().put(action.toString(), action);
        }
    }

    public synchronized Screen getScreen() {
        return screen;
    }

    public Rectangle getViewArea() {
        return viewArea;
    }

    public InputHandler getInputHandler() {
        return inputHandler;
    }

    public Graphics2D getGraphics() {
        return (Graphics2D) screen.getCanvas().getBufferStrategy().getDrawGraphics();
    }

    public void show() {
        screen.getCanvas().getBufferStrategy().show();
    }
}